package perso.marcr.lst.service.impl;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBException;

import org.apache.commons.io.FilenameUtils;
import org.springframework.oxm.XmlMappingException;
import org.springframework.stereotype.Service;

import perso.marcr.lst.api.BufferFile;
import perso.marcr.lst.model.Configuration;
import perso.marcr.lst.model.Scenario;
import perso.marcr.lst.model.ScenarioList;
import perso.marcr.lst.model.Status;
import perso.marcr.lst.model.TaskList;
import perso.marcr.lst.param.GlobalParameters;
import perso.marcr.lst.service.TaskService;
import perso.marcr.lst.util.Xml;
import perso.marcr.util.ConverterByte;
import perso.marcr.util.Unit;

@Service
public class TaskServiceImpl implements TaskService {

	private static List<Scenario> listScenarioUpload = null;
	private static List<Scenario> listScenarioDownload = null;
	private static String taskId = null;
	private static String jobName = null;

	/* (non-Javadoc)
	 * @see perso.marcr.lst.service.TaskService#getTaskListResults()
	 */
	public ScenarioList getTaskListResults() {
		ScenarioList sl = new ScenarioList();
		sl.setListUpload(TaskServiceImpl.listScenarioUpload);
		sl.setListDownload(TaskServiceImpl.listScenarioDownload);
		return sl;
	}

	/* (non-Javadoc)
	 * @see perso.marcr.lst.service.TaskService#save(perso.marcr.lst.model.ScenarioList, java.lang.String, java.lang.String)
	 */
	public void save(ScenarioList dbml, String jobName, String taskId) throws JAXBException, XmlMappingException, IOException
	{
		String szFile = GlobalParameters.getJobDirectory(jobName)+"/"+taskId+TASK_EXTENSION;
		Xml.save(dbml, ScenarioList.class, szFile);
	}

	/* (non-Javadoc)
	 * @see perso.marcr.lst.service.ExecuteScenarioService#read(java.lang.String, java.lang.String)
	 */
	public ScenarioList read(String jobName, String taskId) throws JAXBException
	{		
		String jobsDirectory = GlobalParameters.getJobDirectory(jobName);
		String szFile=jobsDirectory+"/"+taskId+TASK_EXTENSION;

		return (ScenarioList) Xml.read(ScenarioList.class, szFile);
	}

	/* (non-Javadoc)
	 * @see perso.marcr.lst.service.TaskService#delete(java.lang.String, java.lang.String)
	 */
	public void delete(String jobName, String taskId) {
		if(jobName!=null && !jobName.isEmpty() && !jobName.contains("/") && taskId!=null && !taskId.isEmpty())
		{
			String szJobDirectory = GlobalParameters.getJobDirectory(jobName);
			new File(szJobDirectory+"/"+taskId+TASK_EXTENSION).delete();
		}
	}

	/**
	 * @param jobName
	 * @return
	 * @throws JAXBException 
	 */
	public List<TaskList> getAllTasks(String jobName) throws JAXBException {
		assert(jobName!=null && !jobName.isEmpty());

		String jobDirectory = GlobalParameters.getJobDirectory(jobName);		

		File dir = new File(jobDirectory);

		File[] files = dir.listFiles();

		// This filter only returns directories
		FileFilter fileFilter = new FileFilter() {
			public boolean accept(File file) {
				return file.getName().endsWith(TASK_EXTENSION) && !file.getName().equals(ConfigurationServiceImpl.CONFIGURATION_FILE);
			}
		};
		files = dir.listFiles(fileFilter);

		// build result:
		List<TaskList> result = new ArrayList<TaskList>();
		for(int i=0; i<files.length; i++)
		{
			TaskList el = new TaskList();
			String xmlTaskFile=files[i].getName();
			String taskId = FilenameUtils.removeExtension(xmlTaskFile);
			Status status = null;
			if(isRunning(jobName, taskId))
			{
				status=Status.RUNNING;
			}
			else
			{
				ScenarioList listScenario = read(jobName, taskId);
				status = findStatus(listScenario.getListUpload());
			}
			el.setJobName(jobName);
			el.setTaskId(taskId);
			el.setStatus(status);
			result.add(el);
		}
		return result;
	}

	private static Status findStatus(List<Scenario> listScenario)
	{
		Status status = Status.SUCCESS;

		for(int i=0; i<listScenario.size(); i++)
		{
			Scenario scenario = listScenario.get(i);

			if(scenario.getStatus() == null)
			{
				status = Status.UNKNOWN;
				break;
			}      
			else if(scenario.getStatus().equals(Status.ERROR))
			{
				status = Status.ERROR;
				break;
			}
			else if(scenario.getStatus().equals(Status.PENDING))
			{
				status = Status.PENDING;
				break;
			}
			else if(scenario.getStatus().equals(Status.RUNNING))
			{
				status = Status.RUNNING;
				break;
			}
		}

		return status;
	}	

	/* (non-Javadoc)
	 * @see perso.marcr.lst.service.TaskService#isRunning(java.lang.String, java.lang.String)
	 */
	public boolean isRunning(String szJobName, String szTaskId) {		
		return taskId!=null && szTaskId!=null && taskId.equals(szTaskId)
				&& jobName!=null && szJobName!=null && jobName.equals(szJobName);
	}


	public void launchTest(String szJobName, String szTaskId, Configuration configuration) throws XmlMappingException, JAXBException, IOException {
		TaskServiceImpl.taskId = szTaskId;
		TaskServiceImpl.listScenarioUpload = new ArrayList<Scenario>();
		TaskServiceImpl.listScenarioDownload = new ArrayList<Scenario>();
		TaskServiceImpl.jobName = szJobName;

		ScenarioList scenarioList = new ScenarioList();
		scenarioList.setListUpload(listScenarioUpload);
		scenarioList.setListDownload(listScenarioDownload);

		// determine result:
		Scenario scenarioUpload = new Scenario();
		Scenario scenarioDownload = new Scenario();

		String directory = configuration.getHostDirectory();

		double totalSize = configuration.getByteToCopySize();
		double sizeToCopy = ConverterByte.convert(totalSize, configuration.getByteToCopyUnit(), Unit.OCTET);
		boolean bKeepTestFiles = configuration.isKeepTestFiles();

		save(scenarioList, configuration.getJobName(), szTaskId);

		if(configuration.isExecuteScenario1())
		{
			scenarioUpload = new Scenario();
			scenarioDownload = new Scenario();
			listScenarioUpload.add(scenarioUpload);
			listScenarioDownload.add(scenarioDownload);
			scenarioBig(scenarioUpload, scenarioDownload, directory, sizeToCopy, bKeepTestFiles);
		}

		if(configuration.isExecuteScenario2())
		{
			scenarioUpload = new Scenario();
			scenarioDownload = new Scenario();
			listScenarioUpload.add(scenarioUpload);
			listScenarioDownload.add(scenarioDownload);
			scenarioAverage(scenarioUpload, scenarioDownload, directory, sizeToCopy, bKeepTestFiles);
		}

		if(configuration.isExecuteScenario3())
		{
			scenarioUpload = new Scenario();
			scenarioDownload = new Scenario();
			listScenarioUpload.add(scenarioUpload);
			listScenarioDownload.add(scenarioDownload);
			scenarioSmall(scenarioUpload, scenarioDownload, directory, sizeToCopy, bKeepTestFiles);
		}

		if(configuration.isExecuteScenario4())
		{
			scenarioUpload = new Scenario();
			scenarioDownload = new Scenario();
			listScenarioUpload.add(scenarioUpload);
			listScenarioDownload.add(scenarioDownload);
			scenarioVerySmall(scenarioUpload, scenarioDownload, directory, sizeToCopy, bKeepTestFiles);
		}			

		save(scenarioList, configuration.getJobName(), szTaskId);
		listScenarioUpload=null;
		taskId=null;
	}

	/**
	 * @throws IOException
	 * The whole file to copy
	 */
	private static void scenarioBig(Scenario scenarioUpload, Scenario scenarioDownload, String directory, double sizeToCopy, boolean bKeepTestFiles) throws IOException
	{	
		double nbBytesToCopy = sizeToCopy;
		double fileByteSize = sizeToCopy;
		BufferFile bf = new BufferFile(directory, nbBytesToCopy, fileByteSize);
		bf.makeTest(scenarioUpload, scenarioDownload, "big", bKeepTestFiles);
	}

	/**
	 * @throws IOException
	 * Copy 1Go file size.
	 */
	private static void scenarioAverage(Scenario scenarioUpload, Scenario scenarioDownload, String directory, double sizeToCopy, boolean bKeepTestFiles) throws IOException
	{
		double nbBytesToCopy = sizeToCopy;
		double fileByteSize = ConverterByte.convert(1, Unit.GO, Unit.OCTET);
		BufferFile bf = new BufferFile(directory, nbBytesToCopy, fileByteSize);
		bf.makeTest(scenarioUpload, scenarioDownload, "average", bKeepTestFiles);
	}

	/**
	 * @throws IOException
	 * Copy 1 Mo file size.
	 */
	private static void scenarioSmall(Scenario scenarioUpload, Scenario scenarioDownload, String directory, double sizeToCopy, boolean bKeepTestFiles) throws IOException
	{
		double nbBytesToCopy = sizeToCopy;
		double fileByteSize = ConverterByte.convert(1, Unit.MO, Unit.OCTET);
		BufferFile bf = new BufferFile(directory, nbBytesToCopy, fileByteSize);
		bf.makeTest(scenarioUpload, scenarioDownload, "small", bKeepTestFiles);
	}

	/**
	 * @throws IOException
	 * Copy 200 Ko file size.
	 */
	private static void scenarioVerySmall(Scenario scenarioUpload, Scenario scenarioDownload, String directory, double sizeToCopy, boolean bKeepTestFiles) throws IOException
	{
		double nbBytesToCopy = sizeToCopy;
		double fileByteSize = ConverterByte.convert(200, Unit.KO, Unit.OCTET);
		BufferFile bf = new BufferFile(directory, nbBytesToCopy, fileByteSize);
		bf.makeTest(scenarioUpload, scenarioDownload, "verysmall", bKeepTestFiles);
	}		
}
